# -*- coding: utf-8 -*-
'''
#----------------------------------------------------------------------------------------
# 功能：svn版本合并
#----------------------------------------------------------------------------------------
'''
import argparse
from flib.utils import *
from flib.SVN import SVN, SvnRecord


class MyException(Exception):
    def __init__(self, err):
        self.err = err
    def __str__(self):
        return self.err

def toJenkins(v):
    return "{version}:{log}@{author}".format(version=v.version,author=v.author,log=v.log)

@quit
def safe_check_output(*args, **kwargs):
    return check_output(*args, **kwargs)

@quit
def safe_exec(*args, **kwargs):
    return exec_command(*args, **kwargs)

def merge(host,from_branch, to_branch, dst_dir, versions, commit_each = False):
    '''
    @param：host svn版本库host
    @param：from_branch 源分支
    @param：to_branch 目标分支
    @param：dst_dir 目标分支本地地址
    @param: versions 需要合并的记录，源分支记录
    '''
    if to_branch == "trunk":
        ZLPrint("[error]", "不能Merge到trunk.")
        exit(1)
    elif from_branch == "ob":
        ZLPrint("[error]", "不能从ob分支Merge.")
        exit(1)
    elif from_branch == to_branch:
        ZLPrint("[error]", "合并源分支和目标分支一致.")
        exit(1)
    to_url = SVN.make_svn_url(host, to_branch)
    #本地分支存在
    if os.path.exists(dst_dir):
        infos = safe_check_output("svn info {path}".format(path=dst_dir))
        if infos[2][5:] != to_url:
            ZLPrint("[error]", "本地分支不是{to_branch}".format(to_branch=to_branch))
            exit(1)
    else:
        ZLPrint("[error]", "本地不存在目标分支{to_branch}".format(to_branch=to_branch))
        exit(1)
    ZLPrint("更新目标分支：{to_branch}@{dst_dir}".format(to_branch=to_branch,dst_dir=dst_dir))
    safe_exec('''svn update --accept theirs-full "{dst_dir}"'''.format(dst_dir=dst_dir))
    #取出合并过的记录
    merge_records = SVN.get_merge_record_from_branch(to_url, from_branch)
    def merge_one(host, from_branch, to_branch, version, dst_dir, merge_records=None,commit_list=list(),commit_records=list(), commit_each = False):
        ZLPrint("开始合并，从{version}@{from_branch}到{to_branch}".format(from_branch=from_branch, to_branch=to_branch,version=version))
        from_url = SVN.make_svn_url(host, from_branch)
        to_url = SVN.make_svn_url(host, to_branch)
        record = SVN.get_version_log(from_url, version)
        if not record:
            ZLPrint("[error]", "分支{from_branch}找不到记录{version}".format(from_branch=from_branch, version=from_branch))
            exit(1)
        if not merge_records:
            merge_records = SVN.get_merge_record_from_branch(to_url, from_branch)
        if merge_records and version in merge_records:
            ZLPrint("[error]", "记录{version}已经合并过".format(version=version))
            exit(1)

        results = safe_check_output("svn merge -c {version} {from_url} {dst_dir}".format(from_url=from_url, dst_dir=dst_dir, version=version))

        if results:
            for v in results:
                if v.find('C    ') != -1: #有冲突发生
                    ZLPrint("[error]", "有冲突发生，终止合并。", v[5:])
                    exit(1)
                elif v.find('U    ') != -1:
                    if not v[5:] in commit_list: commit_list.append(v[5:])
                    ZLPrint("        ", v[5:])
                elif v.find(' U   ') != -1:
                    if not v[5:] in commit_list: commit_list.append(v[5:])
                    ZLPrint("        ", v[5:])
                elif v.find(' G   ') != -1:
                    if not v[5:] in commit_list: commit_list.append(v[5:])
                    ZLPrint("        ", v[5:])
        if commit_each:
            commit_log = "Merged revision(s) {version} from {from_branch}:\n{author}\n{log}".format(
                version=version,
                from_branch=from_branch,
                author=(SVN.username or "").rstrip('\n'),
                log=record.log)
            flogfile = os.path.join(os.getcwd(), "commit_log.txt")  # .replace("\\", "/")
            flog = open(flogfile, "w")
            flog.write(toGBK(commit_log))
            flog.close()
            commit_files = ""
            for f in commit_list:
                ZLPrint("        ", f)
                commit_files = commit_files + "'{file}' ".format(file=f)
                safe_exec('''svn update --accept theirs-full "{dst_dir}"'''.format(dst_dir=dst_dir))
            ZLPrint("提交合并修改至版本库")
            safe_exec("svn ci -F '{flogfile}' {files}".format(flogfile=flogfile, files=commit_files))
            #safe_exec(cmds='''svn ci -m "{message}" {files}'''.format(message=commit_log, files=commit_files))
        else:
            commit_records.append(record)
    # 记录排序
    # 从小到大合并比较靠谱
    versions = sorted(versions,lambda a,b:cmp(a,b))
    commit_list = []
    commit_versions = ""
    commit_records = []
    for version in versions:
        if commit_each: commit_list = []
        merge_one(host,from_branch,to_branch,version, dst_dir, merge_records, commit_list, commit_records, commit_each)
        commit_versions += "{version}, ".format(version=version)

    if not commit_each:
        commit_versions = commit_versions[:-2]
        logmessage = ""
        for record in commit_records:
            logmessage += record.log + "\n"
        commit_log = "Merged revision(s) {versions} from {from_branch}:\n{author}\n{log}".format(versions=commit_versions,
                                                                                                from_branch=from_branch,
                                                                                                author=(SVN.username or "").rstrip('\n'),
                                                                                                log=logmessage)
        flogfile = os.path.join(os.getcwd(), "commit_log.txt") #.replace("\\", "/")
        flog = open(flogfile, "w")
        flog.write(toGBK(commit_log))
        flog.close()
        commit_files = ""

        for f in commit_list:
            ZLPrint("        ", f)
            commit_files = commit_files + "'{file}' ".format(file=f)
        ZLPrint("提交版本库")
        safe_exec('''svn update --accept theirs-full "{dst_dir}"'''.format(dst_dir=dst_dir))
        safe_exec("svn ci -F '{logfile}' {files}".format(logfile=flogfile, files=commit_files))

    ZLPrint("[success]合并完成。")

def main():
    parser = argparse.ArgumentParser()
    parser.add_argument("--svn-host", help="svn主地址", type=str, default="http://10.236.192.18/svn/seven_client")
    parser.add_argument("--from-branch", help="源分支", type=str, default="trunk")
    parser.add_argument("--to-branch", help="目标分支", type=str, default="pre_obn")
    parser.add_argument("--user", help="svn用户", type=str, default="")
    parser.add_argument("--password", help="svn用户", type=str, default="")
    parser.add_argument("--filters", help="过滤log", type=str, default="")
    parser.add_argument("--search-limit", help="最大搜索记录", type=int, default=1000)
    parser.add_argument("--branch-dir", help="本地目标分支", type=str, default="F:/Seven/branches/ob_next/seven_client")
    parser.add_argument("--merge-versions", help="需要指定合并的记录", type=str, default="")
    parser.add_argument("--op", help="操作", type=str, default="show-unmerge-records")
    parser.add_argument("--commit-each", help="多个记录分多次提及，默认一次提交", action="store_true")
    parser.add_argument("--not-stop_on_copy", help="不仅仅只搜索切分支后的记录", action="store_true")
    args = parser.parse_args()

    SVN.username = args.user
    SVN.password = args.password
    if args.op == "show-unmerge-records":
        #定义合并规则，暂时不允许跨分支合并
        rules = {
            "pre_obn":"trunk",
            "ob_next":"trunk",
            "ob":"ob_next",
            "ios_beta":"ob",
        }
        if args.from_branch == args.to_branch:
            ZLPrint("[error]","目标分支和源分支一样")
            return
        elif rules[args.to_branch] != args.from_branch:
            ZLPrint("[error]","不允许直接从{from_branch}合并到{to_branch}".format(from_branch=args.from_branch,to_branch=args.to_branch))
            return
        #拼接versions到jinkins
        filters = args.filters.split(',')
        filters.append("\nauto commit exported resource@gz_jenkins")
        filters.append("\nauto commit by jenkins:wangyongdong @gz_jenkins")
        filters.append("\nauto commit by jenkins@wuguohui")
        filters.append("\nauto commit by jenkins: wanglei@gz_jenkins")
        filters.append("\nauto commit by jenkins: lidengfeng@gz_jenkins")
        filters.append("\nauto by jenkins:lidengfeng@gz_jenkins")
        records = SVN.get_unmerge_records(args.svn_host, args.from_branch, args.to_branch, args.search_limit, filters = filters, stop_on_copy=not args.not_stop_on_copy)
        if not records:
            raise MyException("can not get unmerged versions")
        sout = ""
        for v in records:
            sout += "\n" + "{message}".format(message=toJenkins(v)).strip("\n").replace("\n", "").replace(",", " ")
        print sout
    elif args.op == "merge":
        versions = args.merge_versions.split(',') #jenkins传入进来的是按照逗号分隔
        records = []
        for v in versions:
            r = SvnRecord.createSvnRecordFromString(v)
            if r: records.append(r.version)
        if not records:
            ZLPrint("没有可以合并的记录")
            exit(0)
        merge(args.svn_host, args.from_branch, args.to_branch, args.branch_dir, records, args.commit_each)
    elif args.op == "show-version-info":
        from_url = SVN.make_svn_url(args.svn_host, args.from_branch)
        versions = args.merge_versions.split(',')  # jenkins传入进来的是按照逗号分隔
        records = []
        for v in versions:
            r = SvnRecord.createSvnRecordFromString(v)
            if r: records.append(r.version)
        if not records:
            ZLPrint("没有可以合并的记录")
            exit(0)
        result = ""
        for record in records:
            result += "\n" + SVN.get_version_log(from_url, record.version).strip("\n").replace("\n", "").replace(",", " ")
        print result
    else:
        raise MyException("not implement.")


if __name__ == '__main__':
    main()